Packages é um componente muito importante do Oracle Database. Com ele podemos agrupar funções, procedures, variáveis, tipos de dados e etc, como componentes em uma biblioteca armazenada no banco, onde vários usuários poderão ter acesso e se beneficiar de tudo que tem no package.
Vamos entender um pouco sobre o funcionamento do package, como ele é inicializado, onde é armazenado, como os seus componentes são compartilhados entre os usuários e assim entender possíveis problemas que podemos enfrentar, e para finalizar, como a PRAGMA SERIALLY_REUSABLE pode nos ajudar nessa situação.
Quando a sessão de um usuário faz referência a um componente do package, o Oracle cria uma instância para aquela sessão. Cada sessão que fizer referência ao mesmo package irá ter a sua própria instância. Essa inicialização do package inclui atribuir valores iniciais a constantes e variáveis públicas e executando a inicialização do package body.
Somente com essas informações podemos prever algo. Como o Oracle cria uma instância do package para cada sessão que faz referência ao mesmo, sendo assim ele é armazenado na User Global Area(UGA). A quantidade de memória necessária na UGA irá aumentar linearmente com o número de usuários, consumindo muita memória e limitando a escalabilidade. Para piorar a situação, essa memória utilizada pelo package persiste até que a sessão seja finalizada, o que as vezes pode demorar bastante, mesmo sem o usuário utilizar mais nada do package!
Algo também pode acontecer mas que pode não ser o desejado, é ao se utilizar variáveis na especificação do package. Se alterarmos esse valor em algum momento da nossa aplicação, uma segunda chamada a essa variável não terá o valor original dela, e sim o modificado, e conforme já foi dito, isso talvez não seja o desejado. Isso é exemplificado na Listagem 1.
Listagem 1. Variáveis em um package não SERIALLY_REUSABLE:
01 CREATE OR REPLACE PACKAGE exemplo_otn IS
02 pv_otn NUMBER := 1;
03 END exemplo_otn;
04 /
05
06 BEGIN
07 dbms_output.put_line('Variável OTN: '||exemplo_otn.pv_otn);
08 exemplo_otn.pv_otn := 2;
09 dbms_output.put_line('Variável OTN: '||exemplo_otn.pv_otn);
10 END;
11 /
Nas linhas 01 à 03 foi criado um package bastante simples, apenas para demonstração, com apenas uma variável com valor inicial 1. Nas linhas 06 a 10 foi criado um bloco PL/SQL anônimo para testar o comportamento da variável pública. Na linha 07 o valor é impresso, na linha 08 o valor é alterado e para finalizar o valor é impresso novamente na linha 09. Vejam o resultado disso na Listagem 2.
Listagem 2. Retorno obtido da Listagem 1.
01 Variável OTN: 1
02 Variável OTN: 2
Reparem que a primeira chamada a variável, retornou o valor 1 que era o seu valor inicial. Após alterar o valor para 2, da variável, a segunda chamada, e todas as chamadas subsequentes, terão o valor 2, até que esse valor seja alterado novamente. Para exemplificar, se o bloco anônimo, da Listagem 1, for executado novamente, ele irá imprimir o valor 2 duas vezes e não mais uma, pois o valor 2 ainda estará salvo na UGA!
Com um package sendo declarado como SERIALLY_REUSABLE o estado do package é armazenado no Work Area em uma pool na System Global Area(SGA) e não mais na UGA. Ele persiste somente durante a chamada ao servidor de algum componente do package. Depois dessa chamada, a Work Area é retornada ao pool. Se algum usuário, talvez o mesmo, fizer mais uma chamada, o Oracle irá reutilizar a instância da pool, mas reinicializando-a. Com isso, todas as alterações anteriores feitas no package serão perdidas, pois o Oracle irá atribuir novamente os valores iniciais as variáveis. Outra grande vantagem nisso é a economia de memória, melhorando assim a escalabilidade da nossa aplicação.
Criando um Package SERIALLY_REUSABLE
Vejamos agora, como ficaria o mesmo exemplo anterior, mas agora sendo SERIALLY_REUSABLE.
Listagem 3. SERIALLY_REUSABLE Package:
01 CREATE OR REPLACE PACKAGE exemplo_otn_sr IS
02 PRAGMA SERIALLY_REUSABLE;
03 pv_otn NUMBER := 1;
04 END exemplo_otn_sr;
05 /
Na linha 02 da Listagem 3, adicionamos o PRAGMA SERIALLY_REUSABLE na especificação do nosso package. Como o nosso exemplo foi bastante simples, contendo apenas uma variável, não foi preciso criar um body para o package. Mas caso fosse necessário, o PRAGMA SERIALLY_REUSABLE também teria que estar no package body. Vejamos agora o efeito de um package ser SERIALLY_REUSABLE. Vamos utilizar o package que foi criado na Listagem 1 e na Listagem 3.
Listagem 4. Efeito do SERIALLY_REUSABLE:
01 BEGIN
02 --alterar os valores das variáveis públicas do dois package
03 exemplo_otn.pv_otn := 2;
04 exemplo_otn_sr.pv_otn := 2;
05 END;
06 /
07
08 BEGIN
09 dbms_output.put_line(‘Sem ser SERIALLY_REUSABLE: ’||exemplo_otn.pv_otn);
10 dbms_output.put_line(‘Sendo SERIALLY_REUSABLE: ’||exemplo_otn_sr.pv_otn);
11 END;
12 /
No primeiro bloco, nas linhas 01 à 05, foi feito uma alteração nos valores das variáveis de cada package, sendo um SERIALLY_REUSABLE e o outro não. No segundo bloco anônimo, nas linhas 08 à 11, é exibido o valor de cada uma das variáveis dos seus respectivos packages, vejamos agora a diferença entre os dois na listagem a seguir. Lembrando que por se tratar de blocos PL/SQL diferentes, são consideradas duas chamadas ao servidor diferentes.
Listagem 5. Retorno obtido da Listagem 4:
01 Sem ser SERIALLY_REUSABLE: 2
02 Sendo SERIALLY_REUSABLE: 1
Perceba a diferença dos valores retornados. Primeiro o package sem ser SERIALLY_REUSABLE retorna o valor 2, que foi o valor modificado no bloco anterior, isso acontece por que o package ainda reside na memória, na UGA. Já no caso do pacakge SERIALLY_REUSABLE o valor retornou para o inicial,que no caso foi 1. Isso ocorro por que, após uma chamada no servidor, que foi o caso do primeiro bloco, o Oracle fecha qualquer cursor aberto, libera memória e retorna o package para o pool, para que ele possa ser reutilizado. Mas na próxima chamada ele terá os valores iniciais novamente, que foi exatamente o que aconteceu.
>Tércio Costa Formado em Ciências da Computação pela UFPB com experiência em Servidores Windows Server e Linux e banco de dados Oracle desde 2008 juntamente com os seus serviços. Desenvolvimento de Sistemas em Java SE com banco de dados Oracle e MySQL. Certificado Oracle Certified SQL Expert, mantendo o blog https://oraclepress.wordpress.com/ reconhecido pela OTN e articulista no portal http://www.profissionaloracle.com.br/gpo
Este artigo foi revisto pela equipe de produtos Oracle e está em conformidade com as normas e práticas para o uso de produtos Oracle.